package com.gitee.wsl.struct.router.trie

import com.gitee.wsl.func.consumer.Consumer
import com.gitee.wsl.struct.tree.sample.trie.MatchResult
import com.gitee.wsl.struct.tree.sample.trie.Trie
import com.gitee.wsl.struct.tree.sample.trie.TrieNode

class TriePathRouter<E> : Trie<MutableList<RouteValue<E>>>() {

    fun addPathPattern(pattern: String, value: E) {
        val list = parseRoute(pattern)

        if (list.isEmpty()) {
            makeNode(
                emptyList(),
                Consumer<TrieNode<MutableList<RouteValue<E>>>> { node: TrieNode<MutableList<RouteValue<E>>> ->
                    addValue(node, list, value)
                })
        } else {
            makeNode(list,
                Consumer<TrieNode<MutableList<RouteValue<E>>>> { node: TrieNode<MutableList<RouteValue<E>>> ->
                    val varNames = getVarNames(list)
                    val last = varNames[varNames.size - 1]
                    val tillEnd = last != null && last.startsWith("*")
                    node.isTillEnd = tillEnd
                    addValue(node, varNames, value)
                })
        }
    }

    fun matchPath(path: String): MatchResult<MutableList<RouteValue<E>>>? {
        return match(this.parseRoute(path))
    }

    fun parseRoute(path: String): List<String> {
        var path = path
        if (path.startsWith("/")) path = path.substring(1)
        if (path.endsWith("/")) path = path.substring(0, path.length - 1)
        return  path.split('/')  //StringHelper.split(path, '/')
    }

    private fun getVarNames(list: List<String>): List<String?> {
        val varNames: MutableList<String?> = ArrayList(list.size)
        for (name in list) {
            if (name.startsWith("{") && name.endsWith("}")) {
                varNames.add(name.substring(1, name.length - 1))
            } else {
                varNames.add(null)
            }
        }
        return varNames
    }

    private fun addValue(
        node: TrieNode<MutableList<RouteValue<E>>>,
        varNames: List<String?>,
        value: E,
    ) {
        var list = node.value
        if (list == null) {
            list = ArrayList<RouteValue<E>>()
            node.value = list
        }
        list.add(RouteValue(varNames, value))
    }
}
